import argparse
import sys
import traceback
from typing import List, Optional

from PyQt5.QtGui import QGuiApplication
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import Qt, QRect

from .hdmi_ui import HdmiFullScreenWindow
from .sys_display_control import ExclusiveHdmiGuard
from .slideshow import PhotoSlideshow
from .config import discover_and_load_config, merge_args_with_config
from .fancy_slideshow import FancySlideshow


def parse_arguments(argv: List[str]) -> argparse.Namespace:
    parser = argparse.ArgumentParser(
        description="Cat Photo UI - HDMI fullscreen launcher",
    )
    parser.add_argument(
        "--screen-index",
        type=int,
        default=None,
        help="目标屏幕索引（0 开始）；默认自动选择 HDMI 屏或非主屏",
    )
    parser.add_argument(
        "--screen-name",
        type=str,
        default=None,
        help="目标屏幕名称匹配（包含匹配）；优先级高于索引",
    )
    parser.add_argument(
        "--prefer-hdmi",
        action="store_true",
        default=True,
        help="优先选择名称包含 HDMI 的屏幕（默认）",
    )
    parser.add_argument(
        "--no-prefer-hdmi",
        dest="prefer_hdmi",
        action="store_false",
        help="关闭 HDMI 名称优先选择",
    )
    parser.add_argument(
        "--windowed",
        action="store_true",
        help="以窗口模式显示（用于调试）",
    )
    parser.add_argument(
        "--exclusive-hdmi",
        action="store_true",
        help="独占HDMI：临时解绑fbcon并降低日志级别（需要root）",
    )
    parser.add_argument(
        "--photo-dir",
        type=str,
        default="/mnt/tfcard/nextcloud_share/手机相册",
        help="相册目录（默认指向你的TF卡同步目录）",
    )
    parser.add_argument(
        "--interval",
        type=int,
        default=8,
        help="轮播间隔（秒）",
    )
    parser.add_argument(
        "--shuffle/--no-shuffle",
        dest="shuffle",
        default=True,
        action="store_true",
        help="随机顺序播放（默认开启）",
    )
    parser.add_argument(
        "--people-priority",
        action="store_true",
        help="人物优先轮播（需要OpenCV，未安装时自动降级）",
    )
    parser.add_argument(
        "--people-weight",
        type=float,
        default=2.0,
        help="人物图片的抽样权重，默认2.0（越大越偏向人物）",
    )
    parser.add_argument(
        "--config",
        type=str,
        default=None,
        help="指定 TOML 配置文件路径；未指定则按默认路径查找",
    )
    parser.add_argument(
        "--fancy",
        action="store_true",
        help="启用炫酷轮播动画（卡片旋转、白边框、飘落、堆叠与渐隐）",
    )
    parser.add_argument(
        "--angle-range",
        type=int,
        default=15,
        help="卡片随机旋转角度范围（度）",
    )
    parser.add_argument(
        "--height-min",
        type=float,
        default=0.6,
        help="卡片最小高度占屏幕高度比例",
    )
    parser.add_argument(
        "--height-max",
        type=float,
        default=1.0,
        help="卡片最大高度占屏幕高度比例",
    )
    parser.add_argument(
        "--stack-size",
        type=int,
        default=4,
        help="同时保留在屏幕上的卡片数量（旧卡片渐隐移除）",
    )
    parser.add_argument(
        "--in-duration",
        type=int,
        default=1200,
        help="入场动画时长（毫秒）",
    )
    parser.add_argument(
        "--out-duration",
        type=int,
        default=800,
        help="退场渐隐时长（毫秒）",
    )
    return parser.parse_args(argv)


def pick_target_screen(app: QGuiApplication, args: argparse.Namespace):
    screens = app.screens()
    if not screens:
        return None

    if args.screen_name:
        name_lower = args.screen_name.lower()
        for s in screens:
            if name_lower in s.name().lower():
                return s

    if args.screen_index is not None:
        if 0 <= args.screen_index < len(screens):
            return screens[args.screen_index]

    if args.prefer_hdmi:
        for s in screens:
            if "hdmi" in s.name().lower():
                return s

    # Fallback: choose a non-primary screen if available
    primary = app.primaryScreen()
    for s in screens:
        if s is not primary:
            return s

    # Last resort: primary
    return app.primaryScreen()


def run_application(argv: List[str]) -> int:
    args = parse_arguments(argv)

    # 读取并合并配置
    cfg = discover_and_load_config(args.config)
    args = merge_args_with_config(args, cfg)

    with ExclusiveHdmiGuard(enable=args.exclusive_hdmi):
        try:
            qt_app = QApplication(sys.argv)
        except Exception:
            print("QApplication 初始化失败:")
            traceback.print_exc()
            return 1
        target_screen = pick_target_screen(qt_app, args)

        if target_screen is None:
            print("未找到可用屏幕。")
            return 1

        window = HdmiFullScreenWindow()
        window.setAttribute(Qt.WA_NativeWindow, True)

        def apply_to_screen() -> None:
            nonlocal target_screen
            # 重新选择目标屏幕（防止拔插导致对象失效）
            target_screen = pick_target_screen(qt_app, args)
            if target_screen is None:
                return
            screen_geometry: QRect = target_screen.geometry()
            window.setGeometry(screen_geometry)
            window.move(screen_geometry.topLeft())
            if args.windowed:
                if not window.isVisible():
                    window.show()
            else:
                # 确保窗口在目标屏幕并全屏
                if not window.isVisible():
                    window.showFullScreen()
                else:
                    window.showFullScreen()
                if window.windowHandle() is not None:
                    window.windowHandle().setScreen(target_screen)

        # 配置并挂载随机轮播
        try:
            from pathlib import Path
            if args.fancy:
                fancy = FancySlideshow(
                    image_dir=Path(args.photo_dir),
                    interval_ms=max(1000, int(args.interval * 1000)),
                    angle_range_deg=int(args.angle_range),
                    min_height_ratio=float(args.height_min),
                    max_height_ratio=float(args.height_max),
                    stack_size=int(args.stack_size),
                    in_duration_ms=int(args.in_duration),
                    out_duration_ms=int(args.out_duration),
                    shuffle=bool(args.shuffle),
                )
                window.set_fancy_slideshow(fancy)
            else:
                slideshow = PhotoSlideshow(
                    image_dir=Path(args.photo_dir),
                    interval_ms=max(1000, int(args.interval * 1000)),
                    shuffle=bool(args.shuffle),
                    enable_people_priority=bool(args.people_priority),
                    people_weight=float(args.people_weight),
                )
                window.set_slideshow(slideshow)
        except Exception as e:
            print(f"初始化轮播失败: {e}")
            traceback.print_exc()

        # 初次应用
        apply_to_screen()

        # 连接屏幕热插拔信号
        def on_screen_added(_screen):
            # 新屏加入，重新绑定并全屏
            try:
                # 监听新屏的几何变化
                try:
                    _screen.geometryChanged.connect(on_geometry_changed)
                except Exception:
                    pass
                apply_to_screen()
            except Exception:
                pass

        def on_screen_removed(_screen):
            try:
                apply_to_screen()
            except Exception:
                pass

        def on_geometry_changed(*_args, **_kwargs):
            try:
                apply_to_screen()
            except Exception:
                pass

        try:
            qt_app.screenAdded.connect(on_screen_added)
            qt_app.screenRemoved.connect(on_screen_removed)
        except Exception:
            pass

        # 监听现有屏幕的分辨率变化
        for s in qt_app.screens():
            try:
                s.geometryChanged.connect(on_geometry_changed)
            except Exception:
                continue

        try:
            return qt_app.exec_()
        except Exception:
            print("Qt 事件循环异常退出:")
            traceback.print_exc()
            return 1


